/*
 * @Author: fhw
 * @Date: 2022-08-02 14:39:32
 * @Description:
 */
import { HttpException, HttpStatus, Injectable, UseFilters } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { equals, isEmpty, isNil } from 'ramda'
import { checkPassword, throwHttp } from 'src/utlis'
import { Connection, Like, Repository } from 'typeorm'
import { IdDto } from '../common/dto/dto'
import { HttpExceptionFilter } from '../http-exception.filter'
import { GetUserInfoDto, GetUserPageDto, RegisterChatUserDto, UpdateChatUserDto, UpdatePassWordDto, UserFindByIdsDto, ValidateUserDto } from './dto/chat_user.dto'
import { ChatUser, ChatUserResult } from './entities/chat_user.entity'
import { JwtService } from '@nestjs/jwt';
import { ChatUserFriend } from 'src/chat_user_friends/entities/chat_user_friend.entity'
import { ChatUserGroup } from 'src/chat_user_group/entities/chat_user_group.entity'
import { GroupChat } from 'src/group-chat/entities/group-chat.entity'
import { compareSync, hashSync } from 'bcryptjs';
const userSelect = [
  "friends.id",
  "friends.username",
  "friends.account",
  "friends.headimgurl",
  "friends.signature",
  "friends.sex",
  "friends.age",
  "friends.createDate",
  "friends.login_date",
]
const friendSelect = [
  'friend.id',
  'friend.createDate',
  'friend.del',
  'friend.friendsId',
  'friend.isRead',
  'friend.latestNews',
  'friend.latestNewsId',
  'friend.remarks',
  'friend.source',
  'friend.status',
  'friend.userId',
  'friend.verification',
]
const chatUserGroupSelect = [
  'chatUserGroup.createDate',
  'chatUserGroup.groupChat',
  'chatUserGroup.group_id',
  'chatUserGroup.id',
  'chatUserGroup.is_join',
  'chatUserGroup.is_management',
  'chatUserGroup.note',
  'chatUserGroup.unread_num',
  'chatUserGroup.updateDate',
  'chatUserGroup.userId',
  'groupChat',
  "groupMembers.id",
  "groupMembers.username",
  "groupMembers.account",
  "groupMembers.headimgurl",
  "groupMembers.signature",
  "groupMembers.sex",
  "groupMembers.age",
  "groupMembers.createDate",
  "groupMembers.login_date",
]
@Injectable()
export class ChatUserService {
  constructor(
    @InjectRepository(ChatUser)
    private chatUserRepository: Repository<ChatUser>,
    private jwtService: JwtService,
    private readonly connection: Connection,
  ) { }

  // 获取用户数据
  @UseFilters(new HttpExceptionFilter())
  async getUserPage(params: GetUserPageDto): Promise<ChatUserResult> {
    try {
      const pageSize = Number(params.pageSize) ?? 10
      let { pageNum = 0 } = params
      if (pageNum !== 0) {
        pageNum -= 1
      }
      const [data, total] = await this.chatUserRepository.findAndCount({
        where: { account: Like(`%${params.username ?? ''}%`), id: params.id },
        select: ['id', 'account', 'headimgurl', 'signature', 'createDate', 'login_date'],
        cache: true,
        relations: ['groupChat']
      })
      return {
        data,
        total,
        pageSize,
        pageNum: pageNum * pageSize + 1,
      }
    } catch (error) {
      throwHttp(error.message)
    }
  }
  async getUserFindByIds({ ids }: UserFindByIdsDto): Promise<ChatUser[]> {
    try {
      const data = await this.chatUserRepository.find({
        where: ids.map(item => { return { id: item } }),
        select: ['username', 'id']
      })
      return data
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 获取用户信息
  @UseFilters(new HttpExceptionFilter())
  async getUserInfo(params: GetUserInfoDto): Promise<ChatUser> {
    try {
      const { id, account } = params
      if (!id && !account) {
        throwHttp('参数为空')
      }
      const data = await this.chatUserRepository.findOne({
        where: { id, account, del: 1 },
        select: ['id', 'account', 'headimgurl', 'signature', 'createDate', 'login_date', 'username', 'sex', 'age'],
      })
      if (isNil(data)) {
        throwHttp('用户不存在')
        return
      }
      return data
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 注册
  @UseFilters(new HttpExceptionFilter())
  async registerChatUser(params: RegisterChatUserDto): Promise<string> {
    try {
      const { username, password, } = params
      const userInfo = await this.chatUserRepository.findOne({
        where: { username },
      })
      if (!isNil(userInfo)) {
        throwHttp('用户已存在')
      }
      const user = new ChatUser()
      user.username = username
      user.account = username
      user.password = password
      const result = await this.chatUserRepository.manager.save(user)
      if (!isEmpty(result)) {
        return `创建 ${result.username} 成功`
      }
      throwHttp('创建失败')
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 更新用户资料
  @UseFilters(new HttpExceptionFilter())
  async updateChatUser(params: UpdateChatUserDto): Promise<string> {
    try {
      const { username, headimgurl, signature, sex, id,  } = params
      await this.getUserInfo({ id })
      const { affected } = await this.chatUserRepository
        .createQueryBuilder()
        .update('chat_user')
        .set({ username, headimgurl, signature, sex,  })
        .where('id = :id', { id })
        .execute()
      if (affected) {
        return '更新资料成功'
      }
      throw new HttpException(
        {
          status: HttpStatus.BAD_REQUEST,
          message: '更新资料失败',
        },
        HttpStatus.BAD_REQUEST,
      )
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 获取用户联系人与群聊
  @UseFilters(new HttpExceptionFilter())
  async getContacts(userId: string) {
    try {
      const data = { friend: [], chatUserGroup: [] }
      const friend = await this.connection.createQueryBuilder(ChatUserFriend, 'friend')
        // 查询好友信息
        .leftJoinAndMapOne(
          'friend.friends',
          ChatUser,
          'friends',
          'friends.id = friend.friendsId AND friends.del = :del',
          { del: '1' }
        ).select(friendSelect.concat(userSelect))
        .where("friend.userId = :userId AND friend.status = :status", { userId, status: '1' })
        .cache(true).getMany();
      data.friend = friend.map(item => {
        return {
          ...item,
          friendsName: item.friends.username,
          headimgurl: item.friends.headimgurl,
          signature: item.friends.signature,
          classType: 1
        }
      })
      const chatUserGroup = await this.connection.createQueryBuilder(ChatUserGroup, 'chatUserGroup')
        // 查询群聊信息
        .leftJoinAndMapOne(
          'chatUserGroup.groupChat',
          GroupChat,
          'groupChat',
          'groupChat.group_id = chatUserGroup.group_id',
          {}
        )
        // 获取群聊成员
        .leftJoinAndMapMany(
          'userGroup', ChatUserGroup,
          'userGroup',
          'chatUserGroup.group_id = userGroup.group_id',
          {})
        // 查询群聊成员信息
        .leftJoinAndMapMany(
          'chatUserGroup.groupMembers', ChatUser,
          'groupMembers',
          'userGroup.userId = groupMembers.id',
          {})
        .select(chatUserGroupSelect)
        .where("chatUserGroup.userId = :userId AND chatUserGroup.is_join = '1'", { userId })
        .cache(true).getMany();
      data.chatUserGroup = chatUserGroup.map(item => {
        return {
          ...item,
          classType: 2
        }
      })
      return data
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 删除用户
  @UseFilters(new HttpExceptionFilter())
  async delChatUser({ id }: IdDto) {
    try {
      await this.getUserInfo({ id })
      const { affected } = await this.chatUserRepository
        .createQueryBuilder()
        .update('chat_user')
        .set({ del: 0 })
        .where('id = :id', { id })
        .execute()
      if (affected) {
        return '删除成功'
      }
      throwHttp('删除失败')
    } catch (error) {
      throwHttp(error.message)
    }
  }
  /** 登录 */
  @UseFilters(new HttpExceptionFilter())
  async login(params: ValidateUserDto) {
    const { username, password } = params
    const user = await this.chatUserRepository.findOne({
      where: { account: username },
      select: ['username', 'password', 'id'],
    });
    if (!user) {
      throwHttp('用户名或密码不正确')
    };
    if (!compareSync(password, user.password)) {
      throwHttp('用户名或密码不正确')
    }
    const payload = { username: user.username, userId: user.id };  // 把信息存在token
    return {
      user: user,
      token: this.jwtService.sign(payload),
    };
  }
  /** 获取密码强度 */
  @UseFilters(new HttpExceptionFilter())
  async getAccountSecurity(userId: number) {
    try {
      if (isNil(userId)) {
        throwHttp('参数为空')
      }
      const userInfo = await this.chatUserRepository.findOne({
        where: { id: userId, del: 1 },
        select: ['strength']
      })
      if (isNil(userInfo)) {
        throwHttp('用户不存在')
        return
      }
      return {
        strength: userInfo.strength
      }
    } catch (error) {
      throwHttp(error.message)
    }
  }
  /** 修改密码 */
  @UseFilters(new HttpExceptionFilter())
  async updatePassWord(params: UpdatePassWordDto) {
    try {
      const { userId, old_password, new_password } = params
      const userInfo = await this.chatUserRepository.findOne({
        where: { id: userId, del: 1 },
        select: ['password']
      })
      if (isNil(userInfo)) {
        throwHttp('用户不存在')
        return
      }
      if (!compareSync(old_password, userInfo.password)) {
        throwHttp('登录密码不正确')
      }
      const { affected } = await this.chatUserRepository
        .createQueryBuilder()
        .update(ChatUser)
        .set({ password: await hashSync(new_password), strength: checkPassword(new_password) })
        .where('id = :id', { id: userId })
        .execute()
      if (affected) {
        return '密码修改成功'
      }
      throwHttp('密码修改失败')
    } catch (error) {
      throwHttp(error.message)
    }

  }
}
